from typing import Dict, List, Tuple
from dataclasses import dataclass
from shapely.geometry import LineString
import shapely
from math import sqrt


@dataclass
class Instance():
    C: int                                          # number online customers
    K: int                                          # number ODs
    Q: int                                          # RD vehicles load capacity
    T: int                                          # toll？？？
    max_dev: float                                  # maximum detour length（最大绕行距离）
    rho: float                                      # compensation factor for ODs (per distance unit of the detours)
    CF: int                                         # cost factor for ODs (per distance unit travelled)
    nodes: List                                     # vertices (depot + customers + ODs)
    nodesRD: List                                   # vertices (depot + customers)
    nodesRD_WD: List                                # vertices (customers)
    q: [int]                                        # RD demand
    m: [int]                                        # OD demand
    l: [int]                                        # OD capacity
    v: [int]                                        # OD vehicle applicable to toll ？？？
    t: Dict[Tuple[int, int], float]                 # toll on arc？？？
    d_sd: Dict[Tuple[int, int], float]              # distance between nodes for OD without toll
    d: Dict[Tuple[int, int], float]                 # distance between nodes
    dRD: Dict[Tuple[int, int], float]               # distance between nodesRD
    dRD_WD: Dict[Tuple[int, int], float]            # distance between nodesRD_WD
    dcorner: Dict[Tuple[int, int], float]           # corner over which the ark goes
    t_dist: Dict[Tuple[int, int], float]            # dist toll fraction on arc？？？


node = int
Arc = Tuple[int, int]


# 创建单条路径？？？
def create_tour(arcs: Dict[Arc, bool]) -> List[node]:

    # 每一条 arc是 customer_i -> customer_j
    # nodes是前序节点的集合，customer_i 组成的点集合，
    nodes = sorted(set([customer_i for (customer_i, customer_j) in arcs]))

    # 后续节点集合
    successors = [[]]
    while len(successors) < len(nodes):
        successors.append([])

    # 在后续链表中添加元素
    for (i,j) in arcs.keys():
        if arcs[i,j] == True:
            # 将 j 追加到 二维列表 successor的第i个列表中
            # 可能一个节点有多个后续节点，比如说仓库节点
            successors[i] += [j]
    #print("successors: ", successors)

    # length_succ 为路径中所有访问点的个数
    # 后续节点的个数即为总体访问节点的个数
    length_succ = 0
    for i in successors:
        length_succ += len(i)
    #print(length_succ)

    first_node = 0
    tour = [first_node]

    # 下面步骤意味着，已知的x，得到的解中自然就是，将所有的RD订单联接起来。但是万一计算出来的结果中，是多条断断续续的路径怎么办？
    while len(tour) < length_succ:
        next_node = successors[first_node].pop(0)
        tour.append(next_node)
        first_node = next_node
    return tour



# 将生成的一条路径切割成多条路径
# 之前生成的路径可能是：0->7->4->5->0->8->0->9->0
# 将之转化为：0->7->4->5->0, 0->8->0, 0->9->0
def create_routes(tour: List[int]) -> List[List[int]]:
    routes = list()
    routes.append([0])
    tour.remove(0)
    #print(routes)
    #print(tour)
    while len(tour) != 0:
        if tour[0] != 0:
            routes[-1].append(tour[0])
            tour.pop(0)
        else:
            routes[-1].append(0)
            tour.pop(0)
            routes.append([0])
        #print(len(tour))
    routes[-1].append(0)
    return routes



# what's up ???
# 未知计算，可能出自此作者的某一篇论文，增加奇怪的方法，徒增计算难度，毫无意义。
def distance_toll(n_out, n_in):
    ra = LineString([(35, 70), (35, 35), (70, 35)])
    line1 = LineString([n_out, n_in])
    intercept = line1.intersection(ra)

    # 相交于一个点
    if type(intercept) is shapely.geometry.point.Point:
        a = intercept.x, intercept.y # a为此交点
        # 如果是向左下方的，计算交点到收点的距离（计算交点到三角框内点的距离）
        if (n_out[0] <= 35 or n_out[1] <= 35) and (n_in[0] > 35 and n_in[1] > 35):
            distance_toll = sqrt((a[0] - n_in[0]) ** 2 + (a[1] - n_in[1]) ** 2)
        # 如果是向右上方的，计算交点到发点的距离（计算交点到三角框内点的距离）
        elif (n_in[0] <= 35 or n_in[1] <= 35) and (n_out[0] > 35 and n_out[1] > 35):
            distance_toll = sqrt((a[0] - n_out[0]) ** 2 + (a[1] - n_out[1]) ** 2)

        else:
            distance_toll = 0

    # 相交于两个点，distance_toll为两个交点之间的距离
    elif type(intercept) is shapely.geometry.multipoint.MultiPoint:
        a = intercept[0].x, intercept[0].y
        b = intercept[1].x, intercept[1].y
        distance_toll = sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)

    # 都位于右上角 返回 1
    elif n_out[0] > 35 and n_out[1] > 35 and n_in[0] > 35 and n_in[1] > 35:
        tau = 1
        return tau

    # 位于其他方位，返回 0
    else:
        tau = 0
        return tau

    distance = sqrt((n_out[0] - n_in[0]) ** 2 + (n_out[1] - n_in[1]) ** 2)
    tau = distance_toll / distance # 计算比值，比值为小数
    return tau



# 判断 n_out -> n_in 是否可行
# 判断 n_out -> n_in 位于仓库的哪个方位
# 路径通行的可能性
# 我怀疑是作者加入这样一个函数，为了防止人们能看懂他代码的真实意图
def distance_toll_access(n_out, n_in):
    # 表示这三个点构成的三条线
    ra = LineString([(35, 70), (35, 35), (70, 35)])
    # n_out -> n_in 的线段
    line1 = LineString([n_out, n_in])
    # 取它们之间的交集
    intercept = line1.intersection(ra)
    # 如果线段与这三条线相交于一个点
    if type(intercept) is shapely.geometry.point.Point:
        a = intercept.x, intercept.y
        if (n_out[0] <= 35 or n_out[1] <= 35) and (n_in[0] > 35 and n_in[1] > 35):
            tau = 1
        else:
            tau = 0
    # 如果相交于多个顶点（也就是两个顶点）
    elif type(intercept) is shapely.geometry.multipoint.MultiPoint:
        a = intercept[0].x, intercept[0].y
        b = intercept[1].x, intercept[1].y
        tau = 1

    else:
        tau = 0
        return tau
    return tau